﻿#pragma once
#include<iostream>
#include<assert.h>
using namespace std;


class Date
{
	friend ostream& operator<<(ostream& out, const Date& d1);//友元函数声明
	friend istream& operator>>(istream& in, Date& d);
public:
	//构造函数
	Date(int year = 1, int month = 1, int day = 1);

	// 只要不改变调用对象的函数都建议加const
	void Print() const;//将const修饰的成员函数称之为const成员函数  Print隐含的this指针由 Date* const this(指向不能变，内容可以变)变为 const Date* const this（都不能变）
	int GetMonthDay(int year, int month)
	{
		assert(month >= 1 && month<=12);
		static int arr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && ((year % 4 == 0) && (year % 100 != 0) || year % 400 == 0))
		{
			return 29;
		}
		else {
			return arr[month];
		}
	}
	bool Daycheck();

	Date& operator=(const Date& d)//赋值运算重载（默认成员函数）
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

	bool operator==(const Date& a) const;//如果⼀个重载运算符函数是成员函数，则它的第⼀个运算对象默认传给隐式的this指针，因此运算符重载作为成员函数时，参数⽐运算对象少⼀个。
	bool operator!=(const Date& a) const;
	bool operator<(const Date& d) const;//运算符重载函数可以不写在类里面，不过那你要解决成员变量是否可以访问，写在类里面默认第一个对象隐式传给this指针
	bool operator<=(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator>=(const Date& d) const;
	
	Date& operator+=(int day);//这里的返回值不会被销毁所以 可以用引用返回
	//如果返回值类型是 Date（而非引用），则每次调用 operator+= 时都会生成一个当前对象的副本（拷贝构造），这在频繁调用时会有性能开销。返回引用直接指向原对象，避免了拷贝，效率更高
	Date operator+(int day) const;
	

	Date& operator-=(int day);
	// 日期-天数
	Date operator-(int day) const;

	// ++d1; -> d1.operatpr++();
	Date& operator++();
	// d1++; -> d1.operatpr++(1);
	Date operator++(int);//后置++重载时，增加⼀个int形参，跟前置++构成函数重载，⽅便区分
	// --d1; -> d1.operatpr--();
	Date& operator--();
	// d1--; -> d1.operatpr--(1);
	Date operator--(int);

	// 日期-日期  
	int operator-(const Date& d) const;

	//ostream& operator<<(ostream& out)//这一版本有问题，因为传参要看参数顺序，你放到成员函数里默认第一个位置是传this的，所以调用这个函数的时候是 d1 << cout  不符合使⽤习惯和可读性。
	//{
	//	out << _year << "年" << _month << "月" << _day << "日" << endl;
	//	return out;//解决办法就是重载为全局函数
	//}

	Date* operator&()//默认成员函数
	{
		//return this;
		return nullptr;
		//return (Date*)0x00FF1200;
	}

	const Date* operator&()const//⼀般这两个函数编译器⾃动⽣成的就可以够我们⽤了，不需要去显⽰实现。
	{
		//return this;
		return nullptr;
		//return (Date*)0x00FF1240;
	}

private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d1);
istream& operator>>(istream& in, Date& d);